/**************************************************************************
 * @doc PIP
 * @module piputl.C |  
 * Source code used to communicate via the PIP Engine.
 *
 * Product     :   SoftPay 2000 (Global Payment Methodology).
 * <nl>Developer   : 
 * <nl>Notes       :
 *
 * @head3 PIP Functions |
 * @index | PIP
 * @end
 *
 * Copyright (c) 1996-2000 by VeriFone Inc. All rights reserved.
 * 
 * No part of this software may be used, stored, compiled, reproduced,
 * modified, transcribed, translated, transmitted, or transferred, in any form 
 * or by any means whether electronic, mechanical, magnetic, optical, 
 * or otherwise, without the express prior written permission of VeriFone, Inc.
 *  
$Log: /SoftPay/SPK2SIM/Source/PIP/piputl.c $ 
**************************************************************************/
#include <project.h>
#define PIPUTL_C

#include <aclconio.h>
#include <stdio.h>
#include <stdlib.h>
#include <acldev.h>
#include <aclutil.h>
#include <message.h>
#include <aclstr.h>
#include <applidl.h>
#include <xmodem.h>
#include <iso8583.h>
#include <amexhost.h>
#include <string.h>
#include <dbmgr.h>

#ifdef PIP_DEFINED

#ifdef DEBUG_PIPUTL
#define DEBUG_95
#endif

#include <define.h>
#include <transact.h>
#include <operate.h>
#include <tran.h>
#include <ppt.h>
#include <hdt.h>
#include <bmp.h>
#include <msg.h>
#include <pipmsg.h>
#include <packet.h>
#include <mdlfuncs.h>
#include <modem.h>
#include <msgfuncs.h>
#include <spdebug.h>
#include <isoload.h>
#include <mem.h>
#include <isodefs.h>
#include <isoutl.h>
#include <ifldtbl.h>
#include <funcids.h>
#include <table.h>
#include <piputl.h>
#include <trt.h>
#include <revutl.h>
#include <ui.h>
#include <codesec.h>

char szPIPProcCode[PROC_CODE_SIZE + 1];

FUNCTION_TABLE srPIPFuncs[] = {
    {inDefaultModifyBatchRec,               MODIFY_BATCH_REC},
    {0,                                     END_OF_FUNC_TABLE},

};

/********************************************************************************************* 
* @func int | inAddPIPFunctions | 
*       Adds PIP functions to the flexi record.
*
* @rdesc return values.
* @flag int    |  VS_ERR, VS_ESCAPE or VS_SUCCESS
* @end
**********************************************************************************************/

int inAddPIPFunctions(void) {
    short inCount = 0;

    /* Add PIP functions to the flexi record */ 
    do {
        if (inAddFunctionPointer(srPIPFuncs[inCount].inFieldID, srPIPFuncs[inCount].pinFunction) == VS_ERR)
            return (VS_ERR);
        inCount++;
    } while (srPIPFuncs[inCount].inFieldID != END_OF_FUNC_TABLE);

    return(VS_SUCCESS);
}


int inModifyBatchRec(TRANSACTION_OBJECT* pobTran) {
    return(inRunFunction(pobTran, MODIFY_BATCH_REC));
}

int inDefaultModifyBatchRec(TRANSACTION_OBJECT* pobTran) {
    return(VS_SUCCESS);
}

/********************************************************************************************* 
* @func void | vdFreeISO8583Data | 
*       Deallocates the memory for comm, host and variant structures
*
* @parm HOST_8583_DATA | *psrHostData | 
*       Host data structure
*
* @end
**********************************************************************************************/

void vdFreeISO8583Data(HOST_8583_DATA* psrHostData) {
    vdFreeCommData(psrHostData->c8583_data);
    vdFreeHostData(psrHostData);
    vdFreeVariantTables();
}
/********************************************************************************************* 
* @func short | shLoadPIPTransCode |
* Reads Host Tran Table file and selects record that 
* matches the current transaction code. The occurrance of this entry
* is shifted and OR'ed with the table field inTranType to give the
* PIP tran code that is passed to pip_trans
*
* @parm int | inTranCode | 
*       The current transaction code
*
* @rdesc Returns PIP transaction code
* @flag int | VS_ERR
* @end
**********************************************************************************************/

short shLoadPIPTransCode(short  shTranCode) {
    int inResult;
    short shBitMapIndex,
    shPIPTransCode;
    PPT_REC stAmexPIPType;
    FHANDLE hPIPTranTypeFHandle;
    long lnSeekResult,
    lnOffset;
    char szFName[FILENAME_SIZE + 1];


    MEMCLR(szFName, sizeof(szFName));
    strcpy(szFName, szGetHostFileName());
    strcat(szFName, ".PPT");

    memset((char *) &stAmexPIPType, 0x00, sizeof(stAmexPIPType));

    hPIPTranTypeFHandle = open(szFName, O_RDONLY);

    if (hPIPTranTypeFHandle < 0)
        return(VS_ERR);
    shBitMapIndex = 0;

    while (TRUE) {
        lnOffset = (long) (((long) shBitMapIndex * (long) SIZE_PPT_REC) + GEN_VER_SIZE);
        lnSeekResult = lseek(hPIPTranTypeFHandle, lnOffset, SEEK_SET);
        if (lnSeekResult != lnOffset)  /* Invalid index given, return VS_ERR */ {
            close(hPIPTranTypeFHandle);
            return(VS_ERR);
        }

        inResult = read(hPIPTranTypeFHandle, (char *) &stAmexPIPType, SIZE_PPT_REC);
        if (inResult == 0L)          /* End of file reached, invalid index  */ {
            close(hPIPTranTypeFHandle);
            return(VS_ERR);
        }

        if (stAmexPIPType.shTranCode == shTranCode)
            break;
        shBitMapIndex++;
    }

    shPIPTransCode = stAmexPIPType.shTranType;

    if (close(hPIPTranTypeFHandle) < 0)
        return(VS_ERR);

    return(shPIPTransCode);
}

/********************************************************************************************* 
* @func int | set_trans_fields | 
*       This routine takes care of loading the Processing Code,
*       message type identifier and the BitMap corresponding to
*       the Transaction that is passed as input to this routine.
*
* @parm int | host | 
*       Numerical representing the host
* @parm unsigned int | inTransCode | 
*       Transaction type 
*
* @rdesc return values.
* @flag int | VS_ERR 
* @flag int | TRUE
* @end
**********************************************************************************************/

int tset_trans_fields(int host,unsigned short shTransCode) {
    int inLoadBmpStatus;
    short shCode;
    unsigned short shTemp;
    char szProcCode[PROC_CODE_SIZE];
    TRANSACTION_OBJECT* pobTran;

    if ((pobTran = pstGet_pobTran()) == NULL_CH)
        return VS_ERR;

    //pdebug(("--set_trans_fields--"));/**/

    shTemp = shTransCode >> 8;

    // If the PIP engine changed our transaction code to DCP or Reversal 
    // then we want to use theirs to look up the processing code & MTI
    // in the bitmap table otherwise we use our original trans code
    if (shTemp == SEND_REVERSAL_ADVICE || shTemp == DCP_ADVICE || shTemp == DCP_REVERSAL || shTemp == REVERSAL)
        shCode = shTemp;
    else
        inGetTranFlexiData(pobTran, AMEX_PIP_TRANS_CODE, (unsigned char *) &shCode, 2);

    /* Open the Bit map file */
    inLoadBmpStatus = inLoadBitmap(shCode, Mti, stMap8583, (unsigned char *) szProcCode);


    /* Set host specific trans fields    */

    inSetTransFields(pobTran, host, shTransCode, szProcCode);

    /* Load Data from the appln global variable into the Fld table */
    inLoadTransData(pobTran, (char *) stMap8583, psrLoadDataFuncs);

    /* Load Optional Fields */
    inLoadTransData(pobTran, (char *) stOptionalMap, psrLoadDataFuncs);

    /* HOST SPECIFIC */
    return(TRUE);
}

/********************************************************************************************* 
* @func int | inUploadAdvices |
* This function uploads the pending Advice records to the host. 
* This should be called at the end of an ONLINE transaction.
* It also updates the batch record for a particular uploaded advice.
*
* @devnote Note that this function requires that the connection
*          to the host should be existing already.
*
* @rdesc Returns the success.
* @flag int | PIP Engine Return Value for the last uploaded host.
* @flag int | VS_ERR
* @end
**********************************************************************************************/
int inUploadAdvices(VS_BOOL fSettle,TRANSACTION_OBJECT* pobTran,int inISOSendSize,VS_BOOL fReversalFlag) {
    int inRetVal;
    int inTransType;
    int inMaxAdvices = 0;
    char szMessage[RESP_MSG_SIZE + 1];



    if ((psrHostData = psrCreateHostData()) == (HOST_8583_DATA *) NULL_CH) {
        vdFreeHostData(psrHostData);
        vdGetMessageFromThisFile(PIP_MESSAGE_FILE, NO_MEMORY_ERR_MSG, szMessage);
        vdDisplayErrorString(szMessage);
        return (VS_ERR);
    }

    vdGetReversalFileName((char *) stRevFileName, shGetHostGroupRef());
    if ((psrHostData->c8583_data = psrCreateCommData(pobTran, inISOSendSize, fReversalFlag)) == (COMM_8583_DATA *) NULL_CH) {
        vdFreeCommData(psrHostData->c8583_data);
        vdFreeHostData(psrHostData);
        vdGetMessageFromThisFile(PIP_MESSAGE_FILE, NO_MEMORY_ERR_MSG, szMessage);
        vdDisplayErrorString(szMessage);
        return (VS_ERR);
    }

    ((VALIDATION_STRUCT *) (psrHostData->c8583_data->v_parms))->comm_struct = psrHostData->c8583_data;


    /* Disable reversal handling while doing advice upload */
    psrHostData->reverse_flag = 0; 

    /* Get the maximum number of piggy-back transactions for this host */
    if (fSettle == VS_FALSE)
        inMaxAdvices = inGetNumAdv();

    /* Set the PIP transaction type to "Send Advice" mode */
    inTransType = A_SEND_ADVICE;
    /* Start Uploading the offline records to the host */
    do {
        strcpy((char *) srISO.pszField44, "00");
        inRetVal = pip_trans(inTransType, psrHostData);
        if (inRetVal == AMEX_NO_ADVICE) {
            inRetVal = VS_SUCCESS;
            break;
        }
        /* Abort settlement if DCP approval on advice */

        if (!(strncmp((char *) srISO.pszField44, "02", 2)) && (fSettle)) {
            vdSGErrorMessage((long) ADV_UPLOAD_ERR_MSG);
            vdGetMessageFromThisFile(PIP_MESSAGE_FILE, DCP_APPROVAL_MSG, szMessage);
            vdSGRespMsg(szMessage);
            inRetVal = VS_ERR;
            break;
        }
        /* Update the batch record for this transaction if approved */

        if (inRetVal == PIP_APPROVAL) {
            /* if 430 it is approved reversal and there is no batch record */
            if (!(Mti[0] == 0x04 && Mti[1] == 0x30)) {
                if (inModifyBatchRec(pobTran) != VS_SUCCESS) {
                    inRetVal = VS_ERR;
                    break;
                }
            }
        } else {
            /* Offline upload failed stop processing */
            if (fSettle == VS_FALSE)
                break;
            else {
                vdGetMessageFromThisFile(PIP_MESSAGE_FILE, ADVICE_UPLOAD_ERR_MSG, szMessage);
                strcat(szMessage, (char *) srISO.pszField39);
                vdSGRespMsg(szMessage);
                inRetVal = VS_ERR;
                break;
            }
        }
        /* NEED not check for MaxAdvice, loop continously */
        if (fSettle == VS_TRUE) {
            inMaxAdvices = 2;  /* Make sure you enter the loop again */
            continue;
        }
    } while (--inMaxAdvices > 0);  /* Continue till you get tired! */

    vdFreeISO8583Data(psrHostData);


    /* Restore reversal handling  */
    psrHostData->reverse_flag = (unsigned char) fGetReversal(pobTran); 

    if ((inRetVal == VS_SUCCESS) || (inRetVal == VS_ERR))
        return(inRetVal);

    /* Result of offline advice upload processing */
    if ((fSettle == VS_TRUE) && (inRetVal != PIP_APPROVAL))
        return(VS_ERR);

    return(VS_SUCCESS);
}

int PIPUTL_CODE_CHECK(char* a,char* b,short* c,char* d,unsigned char* e) {
    GET_VER(a, b, c, d, e);
    return 1;
}


#endif /* PIP_DEFINED */

#undef PIPUTL_C

